package dk.au.cs.bdsi.mail.domain;

import java.util.Collections;
import java.util.LinkedList;
import java.util.List;


/**
 * Message domain object
 */
public class Mail {
	private String to, from, subject, body;
	private List<Header> headers;
	private MailStatus status;
	
	/**
	 * Construct a new message using the given mandatory fields.
	 * 
	 * @param to Recipient e-mail address
	 * @param from Senders e-mail address
	 * @param subject Subject of message
	 * @param body Body of message
	 * @param status Status of message
	 */
	public Mail(String to, String from, String subject, String body, MailStatus status) {
		this(to, from, subject, body, status, null);
	}
	
	/**
	 * Construct a new message using the given mandatory fields and all headers
	 * in the given headers list. Note that any "to", "from", "subject" and "body" header
	 * fields present in the argument <code>headers</code> will be overridden. 
	 *
	 * @param to Recipient e-mail address
	 * @param from Senders e-mail address
	 * @param subject Subject of message
	 * @param body Body of message
	 * @param status Status of message
	 * @param headers Headers of message
	 */
	public Mail(String to, String from, String subject, String body, MailStatus status, List<Header> headers) {
		this(headers);
		this.to = to;
		this.from = from;
		this.subject = subject;
		this.body = body;
		this.status = status;
	}
	
	/**
	 * Constructs a new message using the given header fields. Fields "to", "from",
	 * "subject" and "body" will be filled into their respective fields and not be
	 * present in the resulting list of headers of this message.
	 * 
	 * @param headers Headers
	 */
	public Mail(List<Header> headers) {
		setHeaders(headers);
			
	}

	/**
	 * @return the to
	 */
	public String getTo() {
		return to;
	}

	/**
	 * @param to the to to set
	 */
	public void setTo(String to) {
		this.to = to;
	}

	/**
	 * @return the from
	 */
	public String getFrom() {
		return from;
	}

	/**
	 * @param from the from to set
	 */
	public void setFrom(String from) {
		this.from = from;
	}

	/**
	 * @return the subject
	 */
	public String getSubject() {
		return subject;
	}

	/**
	 * @param subject the subject to set
	 */
	public void setSubject(String subject) {
		this.subject = subject;
	}

	/**
	 * @return the body
	 */
	public String getBody() {
		return body;
	}

	/**
	 * @param body the body to set
	 */
	public void setBody(String body) {
		this.body = body;
	}

	/**
	 * @return the headers
	 */
	public List<Header> getHeaders() {
		return Collections.unmodifiableList(headers);
	}

	/**
	 * Remove all headers and insert the given list of headers
	 * instead, i.e. any header not present in the new list will
	 * be removed, all overlapping will be overriden with the new ones.
	 * 
	 * @param headers the headers to set
	 */
	public void setHeaders(List<Header> headers) {
		// Reset current list
		this.headers = new LinkedList<Header>();
		
		// Build list of headers and extract known fields
		for (Header h : headers) {
			String name = h.getName();
			String value = h.getValue();
			if (name.equals("to"))
				to = value;
			else if (name.equals("from"))
				from = value;
			else if (name.equals("subject"))
				subject = value;
			else
				this.headers.add(h);
		}
	}

	/**
	 * @return the status
	 */
	public MailStatus getStatus() {
		return status;
	}

	/**
	 * @param status the status to set
	 */
	public void setStatus(MailStatus status) {
		this.status = status;
	}

	/* (non-Javadoc)
	 * @see java.lang.Object#hashCode()
	 */
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((body == null) ? 0 : body.hashCode());
		result = prime * result + ((from == null) ? 0 : from.hashCode());
		result = prime * result + ((headers == null) ? 0 : headers.hashCode());
		result = prime * result + ((status == null) ? 0 : status.hashCode());
		result = prime * result + ((subject == null) ? 0 : subject.hashCode());
		result = prime * result + ((to == null) ? 0 : to.hashCode());
		return result;
	}

	/* (non-Javadoc)
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (!(obj instanceof Mail))
			return false;
		Mail other = (Mail) obj;
		if (body == null) {
			if (other.body != null)
				return false;
		} else if (!body.equals(other.body))
			return false;
		if (from == null) {
			if (other.from != null)
				return false;
		} else if (!from.equals(other.from))
			return false;
		if (headers == null) {
			if (other.headers != null)
				return false;
		} else if (!headers.equals(other.headers))
			return false;
		if (status != other.status)
			return false;
		if (subject == null) {
			if (other.subject != null)
				return false;
		} else if (!subject.equals(other.subject))
			return false;
		if (to == null) {
			if (other.to != null)
				return false;
		} else if (!to.equals(other.to))
			return false;
		return true;
	}

	/* (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		StringBuilder builder = new StringBuilder();
		builder.append("Mail [to=");
		builder.append(to);
		builder.append(", from=");
		builder.append(from);
		builder.append(", subject=");
		builder.append(subject);
		builder.append(", body=");
		builder.append(body);
		builder.append(", headers=");
		builder.append(headers);
		builder.append(", status=");
		builder.append(status);
		builder.append("]");
		return builder.toString();
	}
}